package com.uduemc.biso.node.web.api.service.impl;

import java.awt.Color;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

import javax.activation.MimetypesFileTypeMap;
import javax.imageio.stream.FileImageOutputStream;
import javax.imageio.stream.ImageOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.uduemc.biso.core.extities.center.Host;
import com.uduemc.biso.core.utils.CryptoJava;
import com.uduemc.biso.core.utils.JsonResult;
import com.uduemc.biso.core.utils.RestResult;
import com.uduemc.biso.core.utils.ResultUtil;
import com.uduemc.biso.node.core.entities.HRepertory;
import com.uduemc.biso.node.core.entities.HWatermark;
import com.uduemc.biso.node.core.feign.HWatermarkFeign;
import com.uduemc.biso.node.core.property.GlobalProperties;
import com.uduemc.biso.node.core.utils.SitePathUtil;
import com.uduemc.biso.node.web.api.component.RequestHolder;
import com.uduemc.biso.node.web.api.component.SiteHolder;
import com.uduemc.biso.node.web.api.dto.RequestWatermark;
import com.uduemc.biso.node.web.api.service.RepertoryService;
import com.uduemc.biso.node.web.api.service.WatermarkService;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;

@Service
public class WatermarkServiceImpl implements WatermarkService {

	public final static String BisostaticImgSrc = "//bisostatic.35.cn/site/assets/images/flower_640.jpg";

	@Autowired
	private HWatermarkFeign hWatermarkFeign;

	@Autowired
	private RequestHolder requestHolder;

	@Autowired
	private SiteHolder siteHolder;

	@Autowired
	private RepertoryService repertoryServiceImpl;

	@Autowired
	private GlobalProperties globalProperties;

	@Override
	public String[] makeTestWatermarkName() {
		String downloadFilename = SecureUtil.md5(BisostaticImgSrc) + BisostaticImgSrc.substring(BisostaticImgSrc.lastIndexOf("."));
		String watermarkFilename = "watermark_" + downloadFilename;
		return new String[] { downloadFilename, watermarkFilename };
	}

	@Override
	public String makeWatermarkFilepath(String filename) {
		String makeWatermarkDir = makeWatermarkDir();
		return makeWatermarkDir + File.separator + filename;
	}

	@Override
	public String makeWatermarkDir() {
		Host host = null;
		if (requestHolder != null && requestHolder.getHost() != null) {
			host = requestHolder.getHost();
		} else if (siteHolder != null && siteHolder.getHost() != null) {
			host = siteHolder.getHost();
		}
		String basePath = globalProperties.getSite().getBasePath();
		String dir = SitePathUtil.getUserWatermarkPathByCode(basePath, host.getRandomCode());
		File dirFile = new File(dir);
		if (!dirFile.isDirectory()) {
			FileUtil.mkdir(dirFile);
		}
		return dir;
	}

	@Override
	public JsonResult test() {
		// 测试水印
		String[] makeTestWatermarkName = makeTestWatermarkName();
		String downloadFilename = makeTestWatermarkName[0];
		String watermarkFilename = makeTestWatermarkName[1];
		File downloadFile = new File(makeWatermarkFilepath(downloadFilename));
		File watermarkFile = new File(makeWatermarkFilepath(watermarkFilename));

		if (watermarkFile.isFile()) {
			watermarkFile.delete();
		}

		if (!downloadFile.isFile()) {
			// 下载图片
			HttpUtil.downloadFile("http:" + BisostaticImgSrc, downloadFile);
			if (!downloadFile.isFile()) {
				return JsonResult.assistance();
			}
		}

		HWatermark hWatermark = null;
		try {
			hWatermark = infoByHostId(requestHolder.getHost().getId());
		} catch (IOException e) {
			e.printStackTrace();
		}
		if (hWatermark == null || hWatermark.getType() == null) {
			return JsonResult.assistance();
		}

		Integer type = hWatermark.getType();
		try {
			if (type.intValue() == 1) {
				// 文字
				fontWatermark(hWatermark, downloadFile, watermarkFile);
			} else if (type.intValue() == 2) {
				// 图片水印
				imageWatermark(hWatermark, downloadFile, watermarkFile);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

		Map<String, String> result = new HashMap<>();
		result.put("img", BisostaticImgSrc);
		try {
			result.put("watermark",
					"/api/image/watermark/" + CryptoJava.en("" + requestHolder.getHost().getId()) + "/" + watermarkFilename + "?" + System.currentTimeMillis());
		} catch (Exception e) {
			e.printStackTrace();
		}
		return JsonResult.ok(result);
	}

	@Override
	public HWatermark infoByHostId() throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		Host host = null;
		if (requestHolder != null && requestHolder.getHost() != null) {
			host = requestHolder.getHost();
		} else if (siteHolder != null && siteHolder.getHost() != null) {
			host = siteHolder.getHost();
		}
		Long hostId = host.getId();
		return infoByHostId(hostId);
	}

	@Override
	public HWatermark infoByHostId(long hostId) throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		RestResult restResult = hWatermarkFeign.findIfNotExistByHostId(hostId);
		HWatermark data = ResultUtil.data(restResult, HWatermark.class);
		return data;
	}

	@Override
	public HWatermark save(HWatermark hWatermark) throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		RestResult restResult = hWatermarkFeign.updateById(hWatermark);
		HWatermark data = ResultUtil.data(restResult, HWatermark.class);

		// 删除多余水印图片
		String[] makeTestWatermarkName = makeTestWatermarkName();
		String downloadFilename = makeTestWatermarkName[0];
		String watermarkFilename = makeTestWatermarkName[1];
		String makeWatermarkDir = makeWatermarkDir();
		File[] ls = FileUtil.ls(makeWatermarkDir);
		if (ArrayUtil.isNotEmpty(ls)) {
			for (File file : ls) {
				if (file.getName().equals(downloadFilename) || file.getName().equals(watermarkFilename)) {
					continue;
				}
				file.delete();
			}
		}

		return data;
	}

	@Override
	public HWatermark save(RequestWatermark requestWatermark) throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		HWatermark hWatermark = infoByHostId();
		BeanUtil.copyProperties(requestWatermark, hWatermark, false);
		return save(hWatermark);
	}

	@Override
	public void watermark(Long repertoryId) throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		HRepertory infoByid = repertoryServiceImpl.getInfoByid(repertoryId);
		watermark(infoByid);
	}

	@Override
	public void watermark(HRepertory hRepertory) throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		if (hRepertory == null || hRepertory.getType() == null || hRepertory.getType().shortValue() != (short) 0) {
			return;
		}
		Host host = null;
		if (requestHolder != null && requestHolder.getHost() != null) {
			host = requestHolder.getHost();
		} else if (siteHolder != null && siteHolder.getHost() != null) {
			host = siteHolder.getHost();
		}
		Long hostId = host.getId();
		if (hostId.longValue() != hRepertory.getHostId().longValue()) {
			return;
		}
		HWatermark hWatermark = infoByHostId(hostId);
		if (hWatermark == null || hWatermark.getType() == null) {
			return;
		}

		String basePath = globalProperties.getSite().getBasePath();
		String userPathByCode = SitePathUtil.getUserPathByCode(basePath, host.getRandomCode());
		String filepath = hRepertory.getFilepath();
		String filefullpath = userPathByCode + File.separator + filepath;
		File hRepertoryFile = FileUtil.file(filefullpath);

		Integer type = hWatermark.getType();
		if (type.intValue() == 1) {
			// 文字
			fontWatermark(hWatermark, hRepertoryFile);
		} else if (type.intValue() == 2) {
			// 图片水印
			imageWatermark(hWatermark, hRepertoryFile);
		} else {
			return;
		}
	}

	@Override
	public void watermark(File inFile, File outFile) throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		if (!inFile.isFile()) {
			return;
		}
		Host host = null;
		if (requestHolder != null && requestHolder.getHost() != null) {
			host = requestHolder.getHost();
		} else if (siteHolder != null && siteHolder.getHost() != null) {
			host = siteHolder.getHost();
		}
		Long hostId = host.getId();
		HWatermark hWatermark = infoByHostId(hostId);
		if (hWatermark == null || hWatermark.getType() == null) {
			return;
		}

		Integer type = hWatermark.getType();
		if (type.intValue() == 1) {
			// 文字
			fontWatermark(hWatermark, inFile, outFile);
		} else if (type.intValue() == 2) {
			// 图片水印
			imageWatermark(hWatermark, inFile, outFile);
		} else {
			return;
		}

	}

	@Override
	public void testFontImage(long hostId, HttpServletResponse response)
			throws JsonParseException, JsonMappingException, JsonProcessingException, IOException, Exception {
		HWatermark hWatermark = infoByHostId(hostId);
		String text = hWatermark.getText();
		if (StrUtil.isBlank(text)) {
			return;
		}

		String fontStr = hWatermark.getFont();
		String colorStr = hWatermark.getColor();
		colorStr = colorStr.substring(1);
		Color color = new Color(Integer.parseInt(colorStr, 16));
		Integer bold = hWatermark.getBold();
		Integer fontsize = hWatermark.getFontsize();

		String watermarkFilename = SecureUtil.md5(text + fontStr + fontsize + bold + colorStr) + ".png";
		File watermarkFile = new File(makeWatermarkFilepath(watermarkFilename));

		Font font = new Font(fontStr, bold, fontsize);
		try (ImageOutputStream fontImg = new FileImageOutputStream(watermarkFile);) {
			ImgUtil.createImage(text, font, null, color, fontImg);
		}

		if (watermarkFile.isFile()) {
			String contentType = null;
			FileInputStream openInputStream = null;
			try {
				contentType = new MimetypesFileTypeMap().getContentType(watermarkFile);
				openInputStream = FileUtils.openInputStream(watermarkFile);

				if (openInputStream != null) {
					long size = watermarkFile.length();
					response.setHeader("Accept-Ranges", "bytes");
					response.setHeader("Content-Length", "" + size);
					byte[] temp = new byte[(int) size];
					openInputStream.read(temp, 0, (int) size);
					openInputStream.close();
					byte[] data = temp;
					OutputStream out = response.getOutputStream();
					response.setCharacterEncoding("utf-8");
					response.setContentType(contentType);
					out.write(data);

					out.flush();
					out.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				if (openInputStream != null) {
					try {
						openInputStream.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}

	}

	protected void imageWatermark(HWatermark hWatermark, File hRepertoryFile)
			throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		imageWatermark(hWatermark, hRepertoryFile, hRepertoryFile);
	}

	protected void imageWatermark(HWatermark hWatermark, File inFile, File outFile)
			throws JsonParseException, JsonMappingException, JsonProcessingException, IOException {
		Long repertoryId = hWatermark.getRepertoryId();
		HRepertory watermarkHRepertory = repertoryServiceImpl.getInfoByid(repertoryId);
		if (watermarkHRepertory == null) {
			return;
		}

		Host host = null;
		if (requestHolder != null && requestHolder.getHost() != null) {
			host = requestHolder.getHost();
		} else if (siteHolder != null && siteHolder.getHost() != null) {
			host = siteHolder.getHost();
		}
		String basePath = globalProperties.getSite().getBasePath();
		String userPathByCode = SitePathUtil.getUserPathByCode(basePath, host.getRandomCode());
		String filepath = watermarkHRepertory.getFilepath();
		String filefullpath = userPathByCode + File.separator + filepath;
		File watermarkFile = FileUtil.file(filefullpath);

		Integer size = hWatermark.getSize();
		String watermarkFilename = SecureUtil.md5("" + repertoryId + size) + ".png";
		File watermarkScaleFile = new File(makeWatermarkFilepath(watermarkFilename));

		if (!watermarkScaleFile.isFile()) {
			if (!watermarkScaleFile.getParentFile().isDirectory()) {
				FileUtil.mkdir(watermarkScaleFile.getParentFile());
			}
			ImgUtil.scale(watermarkFile, watermarkScaleFile, (float) size / 100);
		}

		Integer opacity = hWatermark.getOpacity();
		Integer area = hWatermark.getArea();

		imageWatermark(hWatermark, inFile, outFile, watermarkScaleFile, opacity, area);
	}

	// 最终水印的实现
	protected void imageWatermark(HWatermark hWatermark, File hRepertoryFile, File outFile, File watermarkFile, Integer opacity, Integer area) {
		int x = 0;
		int y = 0;

		BufferedImage hRepertoryFileBufferedImage = ImgUtil.read(hRepertoryFile);
		int hRepertoryWidth = hRepertoryFileBufferedImage.getWidth();
		int hRepertoryHeight = hRepertoryFileBufferedImage.getHeight();

		BufferedImage watermarkBufferedImage = ImgUtil.read(watermarkFile);
		int watermarkWidth = watermarkBufferedImage.getWidth();
		int watermarkHeight = watermarkBufferedImage.getHeight();

		if (area == null) {
			area = 9;
		}

		if (area.intValue() == 1) {
			// 左上
			x = -(hRepertoryWidth / 2 - watermarkWidth / 2);
			y = -(hRepertoryHeight / 2 - watermarkHeight / 2);
		} else if (area.intValue() == 2) {
			// 中上
			x = 0;
			y = -(hRepertoryHeight / 2 - watermarkHeight / 2);
		} else if (area.intValue() == 3) {
			// 右上
			x = +(hRepertoryWidth / 2 - watermarkWidth / 2);
			y = -(hRepertoryHeight / 2 - watermarkHeight / 2);
		} else if (area.intValue() == 4) {
			// 左中
			x = -(hRepertoryWidth / 2 - watermarkWidth / 2);
			y = 0;
		} else if (area.intValue() == 5) {
			// 中中
			x = 0;
			y = 0;
		} else if (area.intValue() == 6) {
			// 右中
			x = +(hRepertoryWidth / 2 - watermarkWidth / 2);
			y = 0;
		} else if (area.intValue() == 7) {
			// 左下
			x = -(hRepertoryWidth / 2 - watermarkWidth / 2);
			y = +(hRepertoryHeight / 2 - watermarkHeight / 2);
		} else if (area.intValue() == 8) {
			// 中下
			x = 0;
			y = +(hRepertoryHeight / 2 - watermarkHeight / 2);
		} else if (area.intValue() == 9) {
			// 右下
			x = +(hRepertoryWidth / 2 - watermarkWidth / 2);
			y = +(hRepertoryHeight / 2 - watermarkHeight / 2);
		}

		ImgUtil.pressImage(hRepertoryFile, outFile, ImgUtil.read(watermarkFile), x, y, (float) opacity / 100);
	}

	protected void fontWatermark(HWatermark hWatermark, File hRepertoryFile) throws IOException {
		fontWatermark(hWatermark, hRepertoryFile, hRepertoryFile);
	}

	protected void fontWatermark(HWatermark hWatermark, File inFile, File outFile) throws FileNotFoundException, IOException {
		String text = hWatermark.getText();
		if (StrUtil.isBlank(text)) {
			return;
		}

		String fontStr = hWatermark.getFont();
		String colorStr = hWatermark.getColor();
		colorStr = colorStr.substring(1);
		Color color = new Color(Integer.parseInt(colorStr, 16));
		Integer bold = hWatermark.getBold();
		Integer fontsize = hWatermark.getFontsize();

		String watermarkFilename = SecureUtil.md5(text + fontStr + fontsize + bold + colorStr) + ".png";
		File watermarkFile = new File(makeWatermarkFilepath(watermarkFilename));

		if (!watermarkFile.isFile()) {
			if (!watermarkFile.getParentFile().isDirectory()) {
				FileUtil.mkdir(watermarkFile.getParentFile());
			}
			Font font = new Font(fontStr, bold, fontsize);
			try (ImageOutputStream fontImg = new FileImageOutputStream(watermarkFile);) {
				ImgUtil.createImage(text, font, null, color, fontImg);
			}
		}

		imageWatermark(hWatermark, inFile, outFile, watermarkFile, hWatermark.getOpacity(), hWatermark.getArea());
	}
}
